package com.wonders.hisdoctor.station.project.treat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wonders.his.common.exception.CustomException;
import com.wonders.his.common.utils.StringUtils;
import com.wonders.his.framework.service.TokenService;
import com.wonders.his.framework.utils.oracle.IdUtils;
import com.wonders.hisdoctor.station.constant.ServiceConstant;
import com.wonders.hisdoctor.station.enums.ChargeIndicatorEnum;
import com.wonders.hisdoctor.station.enums.ItemClassEnum;
import com.wonders.hisdoctor.station.enums.OracleSequenceEnum;
import com.wonders.hisdoctor.station.project.base.domain.*;
import com.wonders.hisdoctor.station.project.base.mapper.*;
import com.wonders.hisdoctor.station.project.treat.mapper.TreatMapper;
import com.wonders.hisdoctor.station.project.treat.service.ITreatService;
import com.wonders.hisdoctor.station.project.treat.vo.*;
import com.wonders.hisdoctor.station.util.CommonUtil;
import com.wonders.hisdoctor.station.util.PrecsIdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author zhaogongming
 * @date 2021.2.23 下午 7:42 星期二
 * @desc: 治疗申请_service
 */
@Service
public class TreatServiceImpl implements ITreatService {

    @Autowired
    private OutpOrdersMapper outpOrdersMapper;

    @Autowired
    private OutpOrdersTMapper outpOrdersTMapper;

    @Autowired
    private OutpTreatRecMapper outpTreatRecMapper;

    @Autowired
    private OutpTreatRecTMapper outpTreatRecTMapper;

    @Autowired
    private OutpCipherPrescMapper outpCipherPrescMapper;

    @Autowired
    private OutpCipherPrescDetailMapper outpCipherPrescDetailMapper;

    @Autowired
    private TreatMapper treatMapper;

    @Autowired
    private IdUtils idUtils;

    @Autowired
    private PrecsIdGenerator precsIdGenerator;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private CommonUtil commonUtil;

    /**
     * 项目选择_左列表
     *
     * @param hospitalCode
     * @return
     */
    @Override
    public List<DeptVo> queryDept(String hospitalCode) {
        List<DeptVo> deptVos = treatMapper.queryDept(hospitalCode);
        return deptVos;
    }

    /**
     * 项目选择_列表
     *
     * @param hospitalCode 机构代码
     * @param itemName     项目名称
     * @param deptCode     科室编号
     * @return List<ItemListVo>
     */
    @Override
    public List<ItemListVo> itemList(String hospitalCode, String itemName, String deptCode) {
        return treatMapper.itemList(hospitalCode, itemName, deptCode);
    }

    /**
     * 治疗申请_列表
     *
     * @param visitDate 就诊日期
     * @param patientId 病人ID
     * @param visitNo   就诊序号
     * @param empNo     医生编号
     * @return List<OutpTreatRec>
     */
    @Override
    public List<QueryTreatVo> queryTreatList(Date visitDate, String patientId, Integer visitNo, String empNo) {
        return treatMapper.queryTreatList(visitDate, patientId, visitNo, empNo);
    }

    /**
     * 提交申请_保存
     *
     * @param treatVo 治疗_VO
     * @return Integer
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer save(TreatVo treatVo) {
        List<OutpTreatRec> outpTreatRecs = treatVo.getOutpTreatRecs();
        int itemNo = 0;
        String serialNo = null;
        boolean exeOnlyOne = true;
        List<OutpTreatRec> addList = new ArrayList<>();
        List<OutpTreatRecT> tmpList = new ArrayList<>();
        for (OutpTreatRec outpTreatRec : outpTreatRecs) {
            if (StringUtils.isNotEmpty(outpTreatRec.getAppointNo())) {
                continue;
            }
            if (itemNo == 0) {
                serialNo = idUtils.getNextVal(OracleSequenceEnum.SEQ_OUTP_ORDERS.getCode()).toString();
            }
            outpTreatRec.setSerialNo(serialNo);
            outpTreatRec.setItemNo(++itemNo);
            outpTreatRec.setChargeIndicator(0);
            outpTreatRec.setAppointNo(precsIdGenerator.getPrescId());
            OutpTreatRecT outpTreatRecT = new OutpTreatRecT();
            BeanUtils.copyProperties(outpTreatRec, outpTreatRecT);
            addList.add(outpTreatRec);
            tmpList.add(outpTreatRecT);
            // 主记录表
            if (exeOnlyOne) {
                OutpOrders outpOrders = treatVo.getOutpOrders();
                outpOrders.setOrderDate(new Date());
                outpOrders.setSerialNo(serialNo);
                OutpOrdersT outpOrdersT = new OutpOrdersT();
                BeanUtils.copyProperties(outpOrders, outpOrdersT);
                outpOrdersMapper.insert(outpOrders);
                outpOrdersTMapper.insert(outpOrdersT);
                exeOnlyOne = false;
            }
        }
        // 明细表
        outpTreatRecMapper.insertBatch(addList);
        outpTreatRecTMapper.insertBatch(tmpList);
        return itemNo;
    }

    /**
     * 新版：提交申请_保存，加组合名称
     *
     * @param treatVo 治疗_VO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveNew(TreatVo treatVo) {
        if (CollectionUtils.isEmpty(treatVo.getOutpTreatRecs())) {
            throw new CustomException("请选择治疗申请单");
        }
        //流水号
        String serialNo = idUtils.getNextVal(OracleSequenceEnum.SEQ_OUTP_ORDERS.getCode()).toString();
        //1. add 门诊医嘱处方主记录表
        OutpOrders outpOrders = treatVo.getOutpOrders();
        outpOrders.setOrderDate(new Date());
        outpOrders.setSerialNo(serialNo);
        this.outpOrdersMapper.insert(outpOrders);

        //2. add 门诊医嘱处方主记录临时表
        OutpOrdersT outpOrdersT = new OutpOrdersT();
        BeanUtils.copyProperties(outpOrders, outpOrdersT);
        this.outpOrdersTMapper.insert(outpOrdersT);

        //3. add 检查治疗医嘱明细记录表
        List<OutpTreatRec> outpTreatRecList = new ArrayList<>();
        //4. add 检查治疗医嘱明细记录临时表
        List<OutpTreatRecT> outpTreatRecTList = new ArrayList<>();
        // 项目序号
        AtomicInteger treatIndex = new AtomicInteger(0);

        treatVo.getOutpTreatRecs().stream().collect(Collectors.groupingBy(OutpTreatRec::getCombCode, LinkedHashMap::new, Collectors.toList())).forEach((combCode, groupList) -> {
            //治疗申请单号
            String appointNo = precsIdGenerator.getPrescId();
            for (int i = 0; i < groupList.size(); i++) {
                //3.1 检查治疗医嘱明细记录表
                OutpTreatRec outpTreatRec = groupList.get(i);
                outpTreatRec.setSerialNo(serialNo);
                outpTreatRec.setItemClass(ItemClassEnum.TREAT.getCode());
                outpTreatRec.setChargeIndicator(ChargeIndicatorEnum.ORDERED.getCode());
                outpTreatRec.setItemNo(treatIndex.incrementAndGet());
                outpTreatRec.setAppointNo(appointNo);
                outpTreatRec.setAppointItemNo(outpTreatRec.getItemNo());
                outpTreatRecList.add(outpTreatRec);

                //4.1 检查治疗医嘱明细记录临时表
                OutpTreatRecT outpTreatRecT = new OutpTreatRecT();
                BeanUtils.copyProperties(outpTreatRec, outpTreatRecT);
                outpTreatRecTList.add(outpTreatRecT);
            }
        });
        // 入库
        this.outpTreatRecMapper.insertBatch(outpTreatRecList);
        this.outpTreatRecTMapper.insertBatch(outpTreatRecTList);
        return 1;
    }

    /**
     * 撤销申请_删除
     *
     * @param outpTreatRecs 治疗明细表
     * @return Integer
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer delete(List<OutpTreatRec> outpTreatRecs) {
        //校验
        if (CollectionUtils.isEmpty(outpTreatRecs)) {
            throw new CustomException("请选择治疗申请单！");
        }
        for (OutpTreatRec outpTreatRec : outpTreatRecs) {
            // 已缴费, 已退费, 不能删除.
            if (outpTreatRec.getChargeIndicator() == ChargeIndicatorEnum.PAID.getCode() || outpTreatRec.getChargeIndicator() == ChargeIndicatorEnum.RETURN_PAID.getCode()) {
                throw new CustomException("无法删除已缴费/已退费的申请单！");
            }
        }
        //1. 删除 检查治疗表
        this.outpTreatRecMapper.deleteBatch(outpTreatRecs);
        //2. 删除 检查治疗临时表
        this.outpTreatRecTMapper.deleteBatch(outpTreatRecs);

        for (OutpTreatRec outpTreatRec : outpTreatRecs) {
            String serialNo = outpTreatRec.getSerialNo();
            QueryWrapper<OutpTreatRec> wrapper = new QueryWrapper<>();
            wrapper.eq(ServiceConstant.SERIAL_NO, serialNo);
            if (this.outpTreatRecMapper.selectCount(wrapper) == 0) {
                //3. 删除 处方主记录表
                this.outpOrdersMapper.deleteById(serialNo);
                //4. 删除 处方主记录临时表
                this.outpOrdersTMapper.deleteById(serialNo);
            }
        }
        return 1;
    }

    /**
     * 历史申请_查询
     *
     * @param queryHistoryVo 历史申请_VO
     * @return List<OutpTreatRec>
     */
    @Override
    public List<HistoryTreatVo> queryHistory(QueryHistoryVo queryHistoryVo) {
        return treatMapper.queryHistory(queryHistoryVo);
    }

    /**
     * 治疗申请单_打印
     *
     * @param treatPrintVo 入参
     * @return TreatApplicationFormVo
     */
    @Override
    public List<TreatApplicationFormVo> treatPrint(List<TreatPrintNewVo> treatPrintVo) {
        List<TreatApplicationFormVo> treatApplicationFormVos = treatMapper.treatPrint(treatPrintVo);
        if (!CollectionUtils.isEmpty(treatApplicationFormVos)) {
            treatApplicationFormVos.stream().forEach(p -> {
                p.setTitle(commonUtil.setPrintTitle(p.getHospitalCode()));
                p.setAge(commonUtil.getAge(p.getPatientId()));
            });
        }
        return treatApplicationFormVos;
    }

    /**
     * 保存并打印
     *
     * @param treatVo
     * @param request
     * @return
     */
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public List<TreatApplicationFormVo> saveAndPrint(TreatVo treatVo, HttpServletRequest request) {
//        List<OutpTreatRec> outpTreatRecs = treatVo.getOutpTreatRecs();
//        int itemNo = 0;
//        String serialNo = null;
//        boolean exeOnlyOne = true;
//        List<OutpTreatRec> addList = new ArrayList<>();
//        List<OutpTreatRecT> tmpList = new ArrayList<>();
//        //打印申请参数
//        TreatPrintVo treatPrintVo = new TreatPrintVo();
//        treatPrintVo.setPatientId(treatVo.getOutpOrders().getPatientId());
//        treatPrintVo.setVisitDate(treatVo.getOutpOrders().getVisitDate());
//        treatPrintVo.setVisitNo(treatVo.getOutpOrders().getVisitNo().toString());
//        //获取机构编码
//        LoginUserDTO loginUserDTO = tokenService.getLoginUserDTO(tokenService.getToken(request));
//        String hospitalCode = "";
//        if (loginUserDTO != null && loginUserDTO.getSysSysuserVo() != null) {
//            hospitalCode = loginUserDTO.getSysSysuserVo().getHospitalCode();
//        } else {
//            throw new CustomException("当前登录机构不能为空");
//        }
//        treatPrintVo.setHospitalCode(hospitalCode);
//        List<CompPkVo> compPkVos = new ArrayList<>();
//        //入库
//        for (OutpTreatRec outpTreatRec : outpTreatRecs) {
//            if (StringUtils.isNotEmpty(outpTreatRec.getAppointNo())) {
//                //打印入参
//                CompPkVo compPkVo = new CompPkVo();
//                compPkVo.setSerialNo(outpTreatRec.getSerialNo());
//                compPkVo.setItemNo(outpTreatRec.getItemNo());
//                compPkVos.add(compPkVo);
//                continue;
//            }
//            if (itemNo == 0) {
//                serialNo = idUtils.getNextVal(OracleSequenceEnum.SEQ_OUTP_ORDERS.getCode()).toString();
//            }
//            outpTreatRec.setSerialNo(serialNo);
//            outpTreatRec.setItemNo(++itemNo);
//            outpTreatRec.setChargeIndicator(0);
//            outpTreatRec.setAppointNo(precsIdGenerator.getPrescId());
//            OutpTreatRecT outpTreatRecT = new OutpTreatRecT();
//            BeanUtils.copyProperties(outpTreatRec, outpTreatRecT);
//            addList.add(outpTreatRec);
//            tmpList.add(outpTreatRecT);
//            //打印入参
//            CompPkVo compPkVo = new CompPkVo();
//            compPkVo.setSerialNo(serialNo);
//            compPkVo.setItemNo(itemNo);
//            compPkVos.add(compPkVo);
//            // 主记录表
//            if (exeOnlyOne) {
//                OutpOrders outpOrders = treatVo.getOutpOrders();
//                outpOrders.setOrderDate(new Date());
//                outpOrders.setSerialNo(serialNo);
//                OutpOrdersT outpOrdersT = new OutpOrdersT();
//                BeanUtils.copyProperties(outpOrders, outpOrdersT);
//                outpOrdersMapper.insert(outpOrders);
//                outpOrdersTMapper.insert(outpOrdersT);
//                exeOnlyOne = false;
//            }
//        }
//        // 明细表
//        if (!CollectionUtils.isEmpty(addList)) {
//            outpTreatRecMapper.insertBatch(addList);
//            outpTreatRecTMapper.insertBatch(tmpList);
//        }
//        //获取打印信息
//        treatPrintVo.setCompPkVos(compPkVos);
//        return this.getTreatPrint(treatPrintVo);
//    }

    /**
     * 新版：保存并打印
     *
     * @param treatVo
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<TreatApplicationFormVo> saveAndPrintNew(TreatVo treatVo, HttpServletRequest request) {

        if (CollectionUtils.isEmpty(treatVo.getOutpTreatRecs())) {
            throw new CustomException("请选择治疗申请单");
        }
        //流水号
        String serialNo = idUtils.getNextVal(OracleSequenceEnum.SEQ_OUTP_ORDERS.getCode()).toString();

        //判断：如果全是已开单，不插入
        if (treatVo.getOutpTreatRecs().stream().anyMatch(p -> StringUtils.isEmpty(p.getSerialNo()))) {
            //1. add 门诊医嘱处方主记录表
            OutpOrders outpOrders = treatVo.getOutpOrders();
            outpOrders.setOrderDate(new Date());
            outpOrders.setSerialNo(serialNo);
            this.outpOrdersMapper.insert(outpOrders);

            //2. add 门诊医嘱处方主记录临时表
            OutpOrdersT outpOrdersT = new OutpOrdersT();
            BeanUtils.copyProperties(outpOrders, outpOrdersT);
            this.outpOrdersTMapper.insert(outpOrdersT);
        }

        //3. add 检查治疗医嘱明细记录表
        List<OutpTreatRec> outpTreatRecList = new ArrayList<>();
        //4. add 检查治疗医嘱明细记录临时表
        List<OutpTreatRecT> outpTreatRecTList = new ArrayList<>();
        // 项目序号
        AtomicInteger treatIndex = new AtomicInteger(0);

        //打印请求参数
        List<TreatPrintNewVo> treatPrintList = new ArrayList<>();

        treatVo.getOutpTreatRecs().stream().collect(Collectors.groupingBy(OutpTreatRec::getCombCode, LinkedHashMap::new, Collectors.toList())).forEach((combCode, groupList) -> {
            //治疗申请单号
            String appointNo = precsIdGenerator.getPrescId();
            for (int i = 0; i < groupList.size(); i++) {

                //3.1 检查治疗医嘱明细记录表
                OutpTreatRec outpTreatRec = groupList.get(i);

                if (StringUtils.isNotEmpty(outpTreatRec.getAppointNo())) {
                    //打印入参
                    TreatPrintNewVo treatPrintVo = new TreatPrintNewVo();
                    treatPrintVo.setPatientId(treatVo.getOutpOrders().getPatientId());
                    treatPrintVo.setVisitDate(treatVo.getOutpOrders().getVisitDate());
                    treatPrintVo.setVisitNo(treatVo.getOutpOrders().getVisitNo().toString());
                    treatPrintVo.setSerialNo(outpTreatRec.getSerialNo());
                    treatPrintVo.setItemNo(outpTreatRec.getItemNo());
                    treatPrintList.add(treatPrintVo);
                    continue;
                }

                outpTreatRec.setSerialNo(serialNo);
                outpTreatRec.setItemClass(ItemClassEnum.TREAT.getCode());
                outpTreatRec.setChargeIndicator(ChargeIndicatorEnum.ORDERED.getCode());
                outpTreatRec.setItemNo(treatIndex.incrementAndGet());
                outpTreatRec.setAppointNo(appointNo);
                outpTreatRec.setAppointItemNo(outpTreatRec.getItemNo());
                outpTreatRecList.add(outpTreatRec);

                //4.1 检查治疗医嘱明细记录临时表
                OutpTreatRecT outpTreatRecT = new OutpTreatRecT();
                BeanUtils.copyProperties(outpTreatRec, outpTreatRecT);
                outpTreatRecTList.add(outpTreatRecT);

                //打印入参
                TreatPrintNewVo treatPrintVo = new TreatPrintNewVo();
                treatPrintVo.setPatientId(treatVo.getOutpOrders().getPatientId());
                treatPrintVo.setVisitDate(treatVo.getOutpOrders().getVisitDate());
                treatPrintVo.setVisitNo(treatVo.getOutpOrders().getVisitNo().toString());
                treatPrintVo.setSerialNo(serialNo);
                treatPrintVo.setItemNo(outpTreatRec.getItemNo());
                treatPrintList.add(treatPrintVo);
            }
        });

        // 明细表
        if (!CollectionUtils.isEmpty(outpTreatRecList)) {
            this.outpTreatRecMapper.insertBatch(outpTreatRecList);
            this.outpTreatRecTMapper.insertBatch(outpTreatRecTList);
        }
        //获取打印信息
        return this.treatPrint(treatPrintList);
    }

    /**
     * 存为套餐_保存
     *
     * @param setMealVo 套餐_VO
     * @return int
     */
    @Override
    public int saveSetMeal(SetMealVo setMealVo) {
        Long cipherId = idUtils.getNextVal(OracleSequenceEnum.SEQ_OUTP_CIPHER_PRESC.getCode());
        Long cipherDetailId = outpCipherPrescDetailMapper.getMaxId();

        // 协定处方主表
        OutpCipherPresc outpCipherPresc = setMealVo.getOutpCipherPresc();
        outpCipherPresc.setCipherId(cipherId);
        outpCipherPresc.setCreateTime(new Date());
        outpCipherPrescMapper.insert(outpCipherPresc);

        // 协定处方明细表
        List<OutpCipherPrescDetail> outpCipherPrescDetails = setMealVo.getOutpCipherPrescDetails();
        int i = 0;
        for (; i < outpCipherPrescDetails.size(); i++) {
            outpCipherPrescDetails.get(i).setCipherId(cipherId);
            outpCipherPrescDetails.get(i).setCipherDetailId(cipherDetailId + i + 1);
            outpCipherPrescDetailMapper.insert(outpCipherPrescDetails.get(i));
        }
        return i;
    }
}
